angular.module("ui.ssnau.flexBox", [])
    .directive("flexBox", function () {
        var isDragging = false;
        var $ = angular.element;
        var meta = {};
        var hasBind = false;
        var ndCurtain = $("<div style='position:absolute;width:100%;height:100%;opacity:0;z-index:1000;left:0px;top:0px;'></div>");
        var curtains = [];
        var ndImproveCurtain = null;

        function bindMouseEvent(elem) {
            $(elem).on("mousemove", function (e) {
                if (!isDragging) return;
                var ndElem = meta.delimeter,
                    ndPrev = ndElem.prev(),
                    ndNext = ndElem.next() == ndCurtain ? [] : ndElem.next(),
                    pageX = e.pageX || e.originalEvent.pageX,
                    pageY = e.pageY || e.originalEvent.pageY;


                //adjust prev and next based on order
                if (ndPrev[0].style.order > ndNext[0].style.order) {
                    var tmp;
                    tmp = ndPrev;
                    ndPrev = ndNext;
                    ndNext = tmp;
                }

                if (meta.direction === "row") {
                    processDiff([ndPrev, ndNext], "width", pageX - meta.x, ["+", "-"]);
                }

                if (meta.direction === "column") {
                    processDiff([ndPrev, ndNext], "height", pageY - meta.y, ["+", "-"]);
                }

                //renew meta info
                meta.x = pageX;
                meta.y = pageY;

                //执行fb-onrsize中对应的代码
                ndPrev.data("fbOnresize") && ndPrev.data("fbOnresize")();
                ndNext.data("fbOnresize") && ndNext.data("fbOnresize")();
            });

            $(elem).on("mousedown", ">.delimeter", function (e) {
                processMouseDown(this, e);
                e.preventDefault();
                e.stopPropagation();
            });

            function processMouseDown(ndDelimeter, e) {
                isDragging = true;
                meta = {
                    delimeter: $(ndDelimeter), //delimeter is self
                    direction: flexDirection(elem),
                    x: e.pageX || e.originalEvent.pageX,
                    y: e.pageY || e.originalEvent.pageY
                };
                ndCurtain.appendTo(elem);
                curtains.push(ndCurtain);
                ndCurtain.css("cursor", (meta.direction === "row") ? "col-resize" : "row-resize");
            }

            /**
             * 如果delimeter很小，则不方便定位，故显示出ndImproveCurtain来代理delimeter.
             */
            $(elem).on("mouseover", ">.delimeter", function(e){
                var offset = $(this).offset(),
                    me = $(this),
                    direction = /row/.test(me.css("cursor")) ? "column" : "row";

                ndImproveCurtain && ndImproveCurtain.remove();

                var html = ("<div style='position:fixed;left:{{left}};top:{{top}};cursor:{{cursor}};width:{{width}};height:{{height}};background:rgba(100,100,100,0.3);z-index:1000'></div>")
                            .replace("{{left}}", (direction === "row" ? offset.left : offset.left) + "px")
                    .replace("{{top}}", (direction === "row" ? offset.top : offset.top) + "px")
                    .replace("{{cursor}}", me.css("cursor"))
                    .replace("{{width}}", function(){
                        return direction === "row" ? "10px" : me.width() + "px";
                    })
                    .replace("{{height}}", function(){
                        return direction === "column" ? "10px" : me.height() + "px";
                    });

                ndImproveCurtain = $(html);
                ndImproveCurtain.appendTo($(document.body));
                curtains.push(ndImproveCurtain);
                ndImproveCurtain.on("mousedown", function(e){
                    processMouseDown(me, e);
                    e.preventDefault();
                    e.stopPropagation();
                });
                ndImproveCurtain.on("mouseout", function(){
                    ndImproveCurtain && ndImproveCurtain.remove();
                    ndImproveCurtain = null;
                })
            });
            function clearDragging() {
                isDragging = false;
                meta = {};
                curtains.forEach(function(curtain) {
                    curtain.remove();
                });
                curtains = [];
            }

            $(elem).on("mouseup", clearDragging);

            //only bind globally once
            if (hasBind) return;
            hasBind = true;
            $(document).on("mouseup", clearDragging);
        }

        /**
         *
         * @param nodes Array [JQueryNode]
         * @param demension "width" | "height"
         * @param diff integer
         * @param ops Array ["+" | "-"]
         */
        function processDiff(nodes, demension, diff, ops) {
            var results = [], node;

            for (var i = 0; node = nodes[i]; i++) {
                if (!node.length) {
                    results.push(null);
                    continue;
                }
                ;
                var orig = (demension === "width") ? node.width() : node.height(),
                    result = (ops[i] === "+") ? (orig + diff) : (orig - diff),
                    min = parseInt(window.getComputedStyle(node[0])["min" + demension[0].toUpperCase() + demension.substr(1)]) || 0;

                if (result <= min) return; //Only if there is a result being 0, end this function
                results.push(result);
            }

            results.forEach(function (result, index) {
                    if (nodes[index].length) {
                        if (!nodes[index][0].hasAttribute("fill-flexable")) {
                            nodes[index][0].style.flex = "initial";//基于某种奇怪的原因，还是去掉flex属性比较好
                            nodes[index].css(demension, result + "px");
                        }
                    }
                }
            );
        }

        function flexDirection(elem) {
            var el = elem.length ? elem[0] : elem,
                cs = window.getComputedStyle(el);
            return cs.webkitFlexDirection || cs.flexDirection;
        }

        return {
            restrict: "A",
            link: function (scope, elem) {
                $(elem).css("display", "flex");
                bindMouseEvent(elem);
            }
        };
    })
/**
 * 用法：当元素被resize时，会触发fb-onresize中的代码
 * <div fb-onresize="editor.resize()">
 * 当一个元素的fb-onresize调用时，会联动其所有的子元素。
 */
    .directive("fbOnresize", ['$parse', function ($parse) {
        return function (scope, element, attr) {
            var fn = $parse(attr["fbOnresize"]);

            element.data("fbOnresize", function(isCallFromInside/*Never Pass `true` unless you know it!*/){
                fn(scope);
                if (!isCallFromInside) {
                    var nodes = element.find("[fb-onresize]");
                    angular.forEach(nodes, function(node){
                        $(node).data("fbOnresize")(true);
                    })
                }

            });
        };
    }])

